package de.ur.iw.wiki;

import java.io.IOException;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.lang3.StringEscapeUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import de.hijacksoft.xmldownload.DownloadHelper;

public class WikiDownloader {

	private static ArrayList<WikiPage> cache = new ArrayList<WikiPage>();
	
	private static final String CATEGORY = "Kategorie:";

	public static WikiPage downloadRandomPage()
			throws ParserConfigurationException, SAXException, IOException {
		String name = getRandomName();
		return download(name);
	}

	public static String getRandomName() throws ParserConfigurationException,
			SAXException, IOException {
		Document d = DownloadHelper.parseXmlFromUrl(WikiPage.RANDOM_URL);
		String name = getTitle(d);
		return name;
	}

	private static String getTitle(Document d) {
		NodeList pages = d.getElementsByTagName(WikiPage.PAGE_TAG);
		Node first = pages.item(0);
		if (first != null) {
			String title = first.getAttributes().getNamedItem("title")
					.getNodeValue();
			if (title != null) {
				return title;
			} else {
				return "";
			}
		} else {
			return "";
		}
	}

	/**
	 * 
	 * @param name should look sth like: "Kategorie:Informationswissenschaft"
	 * @return
	 */
	public static WikiPage downloadCategory(String name){
		if(!name.startsWith(CATEGORY)){
			name = CATEGORY+name;
		}
		name = name.replaceAll(" ", "%20");
		WikiPage result = new WikiPage(name);
		org.jsoup.nodes.Document doc;
		try {
			doc = Jsoup.connect(WikiPage.WIKI_CATEGORY_URL.replace("%1", name)).get();
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
		addCategories(result, doc);
		addPages(result, doc);
		cache.add(result);
		return result;
	}

	private static void addCategories(WikiPage page,
			org.jsoup.nodes.Document doc) {
		Elements content = doc.select(".CategoryTreeItem");
		for(int i=0; i<content.size(); i++){
			Element cat = content.get(i);
			String html = cat.html();
			String name = getLinkFromCategory(html);
			Link link = new Link(htmlFormat(name));
			link.getInfo().setInt(LinkInfo.KEY_POSITION_OF_PARAGRAPH, 0);
			link.getInfo().setInt(LinkInfo.KEY_POSITION_IN_PARAGRAPH,(int)( i*100.0/content.size()));
			link.getInfo().setString(LinkInfo.KEY_TYPE, LinkInfo.VAL_CATEGORY);
			page.addCategory(link);
		}
	}
	
	private static void addPages(WikiPage page,
			org.jsoup.nodes.Document doc) {
		Elements content = doc.select("#mw-pages li");
		for(int i=0; i<content.size(); i++){
			Element cat = content.get(i);
			String html = cat.html();
			String name = getLinkFromPage(html);
			Link link = new Link(htmlFormat(name));
			link.getInfo().setInt(LinkInfo.KEY_POSITION_OF_PARAGRAPH, 50);
			link.getInfo().setInt(LinkInfo.KEY_POSITION_IN_PARAGRAPH,(int)( i*100.0/content.size()));
			link.getInfo().setString(LinkInfo.KEY_TYPE, LinkInfo.VAL_LINK);
			page.add(link);
		}
	}
	
	private static String htmlFormat(String name) {
		return StringEscapeUtils.unescapeHtml4(name);
	}

	private static String getLinkFromPage(String html) {
		Pattern pattern = Pattern.compile(WikiPage.PAGE_REGEX);
		Matcher matcher = pattern.matcher(html);
		if (matcher.find()) {
			String rawName = matcher.group();
			return rawName.replaceFirst(WikiPage.PAGE_REGEX_REPLACEMENT, "");
		}else{
			return null;
		}
	}

	private static String getLinkFromCategory(String html) {
		Pattern pattern = Pattern.compile(WikiPage.CATEGORY_REGEX);
		Matcher matcher = pattern.matcher(html);
		if (matcher.find()) {
			String rawName = matcher.group();
			return rawName;
		}else{
			return null;
		}
	}

	public static WikiPage download(String name)
			throws ParserConfigurationException, SAXException, IOException {
		
		int cachePosition = cache.indexOf(new WikiPage(name));
		if (cachePosition != -1) {
			return cache.get(cachePosition);
		}

		if(name.startsWith(CATEGORY)){
			return downloadCategory(name);
		}
		
		String url = WikiPage.getUrlFromArticle(name);
		Document d = downloadPage(url);
		String content = getContent(d);
		WikiPage page = formatContent(content, name);
		cache.add(page);
		
		return page;
	}

	private static WikiPage formatContent(String content, String pagename) {
		WikiPage result = new WikiPage(pagename);
		result.setContent(content);
		return (WikiPage) new PageFormatter(content, result, result).getFormattedPage();
	}

	private static String getContent(Document d) {
		NodeList revisions = d.getElementsByTagName(WikiPage.XML_TAG);
		Node current = revisions.item(0);
		if (current != null && current.getChildNodes().getLength() >= 1) {
			return current.getChildNodes().item(0).getNodeValue();
		} else {
			return "";
		}
	}

	private static Document downloadPage(String url)
			throws ParserConfigurationException, SAXException, IOException {
		return DownloadHelper.parseXmlFromUrl(url);
	}

}
